package api

import (
	"errors"
	"fmt"
	"net/http"
	"reflect"

	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	utils "github.com/smash-llj/Nexa-server/utils"
)

type BaseApi struct {
	C      *gin.Context
	Errors error
}

type BuildBaseApiOptions struct {
	C       *gin.Context
	Dto     any //校验数据
	BindUri bool
	BindAll bool
}

type Response struct {
	Status int `json:"status"`
	Code   int `json:"code,omitempty"`
	Msg    any `json:"msg,omitempty"`
	Data   any `json:"data,omitempty"`
}

func NewBaseApi() BaseApi {
	return BaseApi{}
}

func (m Response) IsEmpty() bool {
	return reflect.DeepEqual(m, Response{})
}

func buildStatus(resp *Response, d int) int {
	if resp.Status == 0 {
		resp.Status = d
	}
	return resp.Status
}

func buildResponse(ctx *gin.Context, status int, resp Response) {
	if resp.IsEmpty() {
		ctx.AbortWithStatus(status)
		return
	}
	ctx.AbortWithStatusJSON(status, resp)
}

func Success(c *gin.Context, resp Response) {
	buildResponse(c, buildStatus(&resp, http.StatusOK), resp)
}

func Fail(c *gin.Context, resp Response) {
	buildResponse(c, buildStatus(&resp, http.StatusBadRequest), resp)
}

// BindData 通用校验前端传来的数据
func (b *BaseApi) BindData(options BuildBaseApiOptions) error {
	b.C = options.C
	if options.Dto == nil {
		return nil
	}

	var errResult error
	if options.BindAll || options.BindUri {
		errResult = utils.AppendError(errResult, b.C.ShouldBindUri(options.Dto))
	}
	if options.BindAll || !options.BindUri {
		errResult = utils.AppendError(errResult, b.C.ShouldBind(options.Dto))
	}

	if errResult != nil {
		var ve validator.ValidationErrors
		if errors.As(errResult, &ve) {
			return b.ParseValidateError(ve, options.Dto)
		}
		return fmt.Errorf("验证出现错误: %v", errResult)
	}
	return nil
}

// ParseValidateError 解析tag错误信息
func (b *BaseApi) ParseValidateError(errs validator.ValidationErrors, target any) error {
	var errResult error
	fields := reflect.TypeOf(target).Elem()
	for _, filedError := range errs {
		if field, ok := fields.FieldByName(filedError.Field()); ok {
			errMessage := field.Tag.Get("msg")
			if errMessage == "" {
				errMessage = fmt.Sprintf("%s:%sError", filedError.Field(), filedError.Tag())
			}
			errResult = utils.AppendError(errResult, errors.New(errMessage))
		}
	}
	return errResult
}

// Fail  失败的返回
func (b *BaseApi) Fail(resp Response) {
	Fail(b.C, resp)
}

// Success  成功的返回
func (b *BaseApi) Success(resp Response) {

	Success(b.C, resp)
}
